#include <QtGui>
#include <QtOpenGL\QtOpenGL>
//#define _CHECK_FRAMERATE
#include <math.h>
#include <vector>
using namespace std;
#include "Data.h"
#include "glwidget.h"
//#include "bmp.h"
#include "Gfx.h"
#include "RoomGfx.h"
#include "CalibrationGfx.h"
//New scene goes here
//#include <Windows.h>
#include "FileIO.h"
class CFileIO;

 GLWidget::GLWidget(QWidget *pParent_)
 :QGLWidget(pParent_)
 {
     //frame rate control. The swapinterval must be set to 1 
     QGLFormat cFormat(QGL::SampleBuffers|QGL::DoubleBuffer);
     cFormat.setSwapInterval(1);//
     setFormat(cFormat);
     /////////////////////////////
     _bDataLoaded = false;
     _pGfx = NULL;
     _pData =NULL;
     _nFrameIdx = 0;
 }

 GLWidget::~GLWidget()
 {
     if(_pGfx) delete _pGfx;
     makeCurrent();
 }

void GLWidget::paintGL()
{
    //frame rate testing
    LARGE_INTEGER frequency;        // ticks per second
    LARGE_INTEGER t2; 
    LARGE_INTEGER t3;               // to check if need to sleep
    LARGE_INTEGER t4;               // for how long we slept
    // get ticks per second
    QueryPerformanceFrequency(&frequency);

    QueryPerformanceCounter(&t2);
    double dElapsedTime = double (t2.QuadPart - _t1.QuadPart) / frequency.QuadPart;
    QueryPerformanceCounter(&_t1); // for next frame

    if(_pGfx)
    {    
        try{
            if(_pGfx->exptState()==CGfx::BeforeRun)
            {
                _nCounter = 0;
            }

            _pGfx->updateStatus();
            if(_pGfx->exptState()==CGfx::OnBreak)
            {
                // Render a gray board
                //glColor3f(0.0f,.0f,.0f);
                //glBegin(GL_POLYGON);
                //    glVertex3f(-20.0,-20.0, _pData->gfxNear()+.2);
                //    glVertex3f(-20.0, 20.0, _pData->gfxNear()+.2);
                //    glVertex3f( 20.0, 20.0, _pData->gfxNear()+.2);
                //    glVertex3f( 20.0,-20.0, _pData->gfxNear()+.2);
                //glEnd();
                //glMatrixMode(GL_PROJECTION);                        // Select The Projection Matrix
                //glLoadIdentity();                                    // Reset The Projection Matrix
                //gluPerspective(_pData->gfxFOVy(),_pData->gfxAspectRatio(), _pData->gfxFar(), _pData->gfxFar());
                // Render Text

                QFont cFont1( "Times", 36, QFont::Bold );
                QString qstrText1 = QString("Round %1").arg(_pData->trialIdx()+1);
                QFont cFont2( "Times", 24, QFont::Bold );
                QString qstrText2;
                if(_nFrameIdx%60==0)
                    _pData->setTimer()++;
                if(_pData->breakTime() - _pData->Timer() >= 0)
                    qstrText2 = QString("Take a break for %2 secs.").arg(_pData->breakTime() - _pData->Timer() );
                else
                {
                    qstrText2 = QString("Click to trigger next trial.");
                    if(_pData->CheckForTriggerHelper())
                    {
                        _pGfx->setExptState() = CGfx::NormalView;
                    }
                    if(_nCounter<0)
                    {
                        //_pGfx->setExptState() = CGfx::DuringRun;
                    }
                    else
                    {
                        _nCounter--;
                    }
                    //glMatrixMode(GL_PROJECTION);                        // Select The Projection Matrix
                    //glLoadIdentity();                                    // Reset The Projection Matrix
                    //gluPerspective(_pData->gfxFOVy(),_pData->gfxAspectRatio(), _pData->gfxNear(), _pData->gfxFar());
                }
                //glColor3f(1.f,1.f,1.f);
                //renderText(width()/2-110,height()/2-40,qstrText1,cFont1);
                //renderText(width()/2-180,height()/2+10,qstrText2,cFont2);
            }
            if(_pGfx->exptState()==CGfx::ExpEnd)
            {
                glPushAttrib(GL_COLOR_BUFFER_BIT);
                glPushAttrib(GL_DEPTH_BUFFER_BIT);
                glPushAttrib(GL_CURRENT_BIT);
                //_cTimer->stop();
                glEnable(GL_POLYGON_SMOOTH);
                glEnable(GL_BLEND);
                glEnable(GL_DEPTH_TEST);

                setDatatLoaded()=false;
                QFont cFont1( "Times", 36, QFont::Bold );
                QString qstrText1 = QString("Experiment ends.").arg(_pData->trialIdx()+1);
                QFont cFont2( "Times", 24, QFont::Bold );
                QString qstrText2 = QString("Please contact %1 (Tel:%2).").arg(_pData->experimenter()).arg(_pData->tel());
                glColor3f(1.f,1.f,1.f);
                renderText(width()/2-130, height()/2-40,qstrText1,cFont1);
                renderText(width()/2-200, height()/2+10,qstrText2,cFont2);
                glPopAttrib();
                glPopAttrib();
                glPopAttrib();
            }
            update();
        }
        catch(exception& e)
        {

            QMessageBox::warning(this,QString("Error"),QString(e.what()),QMessageBox::Yes); 
            //_cTimer->stop();
            setDatatLoaded()=false;

            _pGfx->setExptState() = CGfx::ExpEnd;
        }
    }
    
    _nFrameIdx++;
    
    QueryPerformanceCounter(&t3);
    if ((double(t3.QuadPart - t2.QuadPart) / frequency.QuadPart)<.010)
    {
        QFont cFont2( "Times", 10, QFont::Normal );
        if(_pData->checkFrameRate())
        {
            QString qstrText2;
            qstrText2.sprintf("Process Time: %1.4f",double(t3.QuadPart - t2.QuadPart) / frequency.QuadPart);
            glColor3f(1.f,0.f,0.f);
            renderText(width()/2-130, height()-60,qstrText2,cFont2);
        }

        QueryPerformanceCounter(&t4);
        while ((double(t4.QuadPart - t3.QuadPart) / frequency.QuadPart)<.005)// need to sleep for 5 ms to wait for the joystick to response.
        {
            QueryPerformanceCounter(&t4);
        }
        if(_pData->checkFrameRate())
        {
            QString qstrText3;
            qstrText3.sprintf("Wait Time: %1.4f",double(t4.QuadPart - t3.QuadPart) / frequency.QuadPart);
            glColor3f(1.f,0.f,0.f);
            renderText(width()/2-130, height()-80,qstrText3,cFont2);
        }
    }
    //Sleep(5);

    // check frame rate
    if(_pData->checkFrameRate())
    {
        glPushAttrib(GL_COLOR_BUFFER_BIT);
        glPushAttrib(GL_DEPTH_BUFFER_BIT);
        glPushAttrib(GL_CURRENT_BIT);
        //_cTimer->stop();
        glEnable(GL_POLYGON_SMOOTH);
        glEnable(GL_BLEND);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glBlendFunc(GL_ONE,GL_ZERO);

        if(_pData->systemOutput())
            _vFrameRate.push_back(1./dElapsedTime);
        QFont cFont1( "Times", 10, QFont::Normal );
        QString qstrText1 = QString("Frame rate: %1.").arg(1./dElapsedTime);
        glColor3f(1.f,0.f,0.f);
        renderText(width()/2-130, height()-40,qstrText1,cFont1);

        glPopAttrib();
        glPopAttrib();
        glPopAttrib();
    }
    return;
}

 void GLWidget::mousePressEvent(QMouseEvent *event)
 {
 }

 void GLWidget::mouseMoveEvent(QMouseEvent *event)
 {
 }

 void GLWidget::init()
 {
     setDatatLoaded() = true;

     CGfx* pTemp = _pGfx;
     if(_pGfx) delete _pGfx;
     if(QString("CRoomData").contains(_pData->className().c_str()))
         _pGfx = new CRoomGfx(_pData);
     else if(QString("CCalibrationData").contains(_pData->className().c_str()))
         _pGfx = new CCalibrationGfx(_pData); 
     //new scene allocation goes here...
     _pGfx->setExptState() = CGfx::BeforeRun;
     _pData->setScreenHeight() = height();
     _pData->setScreenWidth() = width();
     _pData->setTrialIdx()=0;
     _pData->setTimeIdx()=0;
     _vFrameRate.clear();
     _pGfx->initGL();
 }

 void GLWidget::next()
 {
     if(_pData)
        _pData->setTimeIdx()=0;
     if(_pGfx)
        _pGfx->setExptState() = CGfx::AfterRun;
 }

 void GLWidget::exit()
 {
     saveToFile();
     _vFrameRate.clear();
     if(_pGfx)
        _pGfx->setExptState() = CGfx::ExpEnd;
 }

 void GLWidget::resizeGL( int width, int height )
 {
     if(_pGfx)
        _pGfx->resizeGL(width,height);
 }

 void GLWidget::saveToFile()
 {
     CFileIO cFIO;
     // check existence data directory and create if necessary
     cFIO.CreateCWDir(string("\\data")); // do not add trailing slash! (prefixing a slash is not necessary but ok

     // create filename: prefix + _ ellipse _ + control condition + feedback condition + run# + option training flag
     char cFileName[80];
     sprintf_s(cFileName,80,"System_Output.txt");

     // create file
     cFIO.OpenFileWrite(cFileName);
     {
         // inputs from file and other fixed parameters
         cFIO.WriteStrValToFile(string("Idx"));
         cFIO.WriteTab();
         cFIO.WriteStrValToFile(string("FrameRate"));
         cFIO.WriteEndl();
         for(int i=0;i<(int)_vFrameRate.size();i++)
         {
             cFIO.WriteDblValToFile(i);
             cFIO.WriteTab();
             cFIO.WriteDblValToFile(_vFrameRate[i]);
             cFIO.WriteEndl();
         }
         cFIO.CloseFile();
     }
 }
